#include <iostream>
#include <fstream>
#include "gol.h"
using namespace std;

Gol::Gol(){
    /*  Make sure the table is initialised  */
    _init();

}

Gol::Gol(const char * filename){
    read(filename);
}

void Gol::_init(){
    /*  Initialise all grid values to 0 */
    for (int i=0; i<_gridh; i++){
        for (int j=0; j<_gridw; j++){
            _celltable[j][i] = 0;
        }
    }
    _generation = 0;
}

int Gol::_setcell(int xpos, int ypos, bool cellstate){
    if (xpos < _gridw && xpos >= 0 && ypos < _gridh && ypos >=0){
        _celltable[xpos][ypos] = cellstate;
        return 0;
    }else{
        return -1;
    }
}

void Gol::calculate(){
    /*  We need to make a copy of the grid first */
	int i, j, k, l, count;
	bool grid_copy[_gridw+2][_gridh+2]; // the copy needs to be padded with zeroes around
                                        // the grid so life can't expand infinitely

	for (i=0; i<_gridh+2; i++){  // zero the copy first
		for (j=0; j<_gridw+2; j++){
			grid_copy[j][i] = 0;
		}
	}

	for (i=1; i<_gridh+1; i++){ //then populate the inner grid
		for (j=1; j<_gridw+1; j++){
			grid_copy[j][i] = _celltable[j-1][i-1]; // subtract 1 for the padding at the left and top
		}
	}

	/* 	now use the copy grid to calculate the next generation and update the
		original grid. since arrays are passed by reference, I can chance its
		contents directly	*/

	for (i=1; i<_gridh+1; i++){
		for (int j=1; j<_gridw+1; j++){ //move through each cell except the padding
			count=0;
			for (k=-1; k<2; k++){
				for (l=-1; l<2; l++){
					if (!(k==0 && l==0) && grid_copy[j+k][i+l]) count++;  //count the surrounding cells [3x3]
				}
			}
			if (count==3) _celltable[j-1][i-1] = 1; // conditions for new life
			if (count>3 || count<2) _celltable[j-1][i-1] = 0; // conditions for death
		}
	}
	_generation++;
}

void Gol::show(){
    /*  This function shouldn't actually be in this class, the Gol
        object should be passed to another class that handles display.

        This method makes use of iostream to output the state of the
        Gol array.
        */

	for (int i=0; i<_gridh; i++){
		for (int j=0; j<_gridw; j++){
			if (_celltable[j][i]){
				cout << "X ";
			}else{
				cout << ". ";
			}
		}
		cout << endl;
	}
}

int Gol::get_generation(){
    return _generation;
}

void Gol::read(const char * filename){
    /*  Reads a file with coordinates of living cells
        the file is just x y coordinates separated by a space
        one coordinate per line */

    ifstream f;
    int xpos, ypos;

    _init();
    f.open(filename);
    if (f.is_open()){
        while(f >> xpos >> ypos){
            _setcell(xpos, ypos, true);
        }
        f.close();
    }else{
        cerr << "Unable to open '" << filename << "' for reading" << endl;
    }
}
